﻿namespace MicroCloud.Dependency
{
    /// <summary>
    /// 应用程序服务定位器，可随时正常解析<see cref="ServiceLifetime.Singleton"/>与<see cref="ServiceLifetime.Transient"/>生命周期类型的服务
    /// 如果当前处于HttpContext有效的范围内，可正常解析<see cref="ServiceLifetime.Scoped"/>的服务
    /// 注：服务定位器尚不能正常解析 RootServiceProvider.CreateScope() 生命周期内的 Scoped 的服务
    /// </summary>
    public class ServiceLocator : Disposable
    {
        //字段
        private static readonly Lazy<ServiceLocator> InstanceLazy = new(() => new ServiceLocator());

        private IServiceCollection _services;
        private IServiceProvider _provider;

        /// <summary>
        /// 初始化一个服务定位器 <see cref="ServiceLocator"/> 的新实例
        /// </summary>
        private ServiceLocator()
        { }

        #region 属性
        /// <summary>
        /// 获取 服务器定位器实例
        /// </summary>
        public static ServiceLocator Instance => InstanceLazy.Value;

        /// <summary>
        /// 获取 ServiceProvider是否为可用
        /// </summary>
        public bool IsProviderEnabled => _provider != null;

        /// <summary>
        /// 获取 <see cref="ServiceLifetime.Scoped"/>生命周期的服务提供者
        /// </summary>
        public IServiceProvider ScopedProvider
        {
            get
            {
                IScopedServiceResolver scopedResolver = _provider.GetService<IScopedServiceResolver>();
                return scopedResolver != null && scopedResolver.ResolveEnabled
                    ? scopedResolver.ScopedProvider
                    : null;
            }
        }

        #endregion

        #region 方法
        /// <summary>
        /// 获取当前是否处于 <see cref="ServiceLifetime.Scoped"/> 生命周期中
        /// </summary>
        /// <returns></returns>
        public static bool InScoped()
        {
            return Instance.ScopedProvider != null;
        }

        /// <summary>
        /// 设置应用程序服务集合
        /// </summary>
        /// <param name="services"></param>
        public void SetServiceCollection(IServiceCollection services)
        {
            Check.NotNull(services, nameof(services));
            // Console.WriteLine($@"服务定位器设置应用程序服务集合: {services}");
            //程序集生命周期对象：Microsoft.AspNetCore.WebApplicationServiceCollection
            //区域生命周期对象：Microsoft.Extensions.DependencyInjection.ServiceCollection
            _services ??= services;
        }

        /// <summary>
        /// 设置应用程序服务提供者
        /// </summary>
        /// <param name="provider"></param>
        public void SetApplicationServiceProvider(IServiceProvider provider)
        {
            Check.NotNull(provider, nameof(provider));
            Console.WriteLine($@"服务定位器设置应用程序服务提供者: {provider}");
            //程序集生命周期对象：Microsoft.Extensions.DependencyInjection.ServiceProvider
            //区域生命周期对象：Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope
            _provider ??= provider;
        }

        /// <summary>
        /// 获取所有已注册的 <see cref="ServiceDescriptor"/> 对象
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ServiceDescriptor> GetServiceDescriptors()
        {
            Check.NotNull(_services, nameof(_services));
            return _services;
        }

        /// <summary>
        /// 解析指定类型的服务实例
        /// </summary>
        public T GetService<T>()
        {
            Check.NotNull(_provider, nameof(_provider));

            IScopedServiceResolver scopedResolver = _provider.GetService<IScopedServiceResolver>();
            if (scopedResolver != null && scopedResolver.ResolveEnabled)
            {
                var scopedService = scopedResolver.GetService<T>();
                return scopedService;
            }
            var service = _provider.GetService<T>();
            return service;
        }

        /// <summary>
        /// 解析指定类型的服务实例
        /// </summary>
        /// <param name="serviceType">服务类型</param>
        public object GetService(Type serviceType)
        {
            Check.NotNull(_provider, nameof(_provider));

            IScopedServiceResolver scopedResolver = _provider.GetService<IScopedServiceResolver>();
            if (scopedResolver != null && scopedResolver.ResolveEnabled)
            {
                return scopedResolver.GetService(serviceType);
            }
            return _provider.GetService(serviceType);
        }

        /// <summary>
        /// 解析指定类型的所有服务实例
        /// </summary>
        public IEnumerable<T> GetServices<T>()
        {
            Check.NotNull(_provider, nameof(_provider));

            IScopedServiceResolver scopedResolver = _provider.GetService<IScopedServiceResolver>();
            if (scopedResolver != null && scopedResolver.ResolveEnabled)
            {
                return scopedResolver.GetServices<T>();
            }
            return _provider.GetServices<T>();
        }

        /// <summary>
        /// 解析指定类型的所有服务实例
        /// </summary>
        /// <param name="serviceType">服务类型</param>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            Check.NotNull(_provider, nameof(_provider));

            IScopedServiceResolver scopedResolver = _provider.GetService<IScopedServiceResolver>();
            if (scopedResolver != null && scopedResolver.ResolveEnabled)
            {
                return scopedResolver.GetServices(serviceType);
            }
            return _provider.GetServices(serviceType);
        }

        /// <summary>
        /// 获取指定类型的日志对象
        /// </summary>
        /// <typeparam name="T">非静态强类型</typeparam>
        /// <returns>日志对象</returns>
        public ILogger<T> GetLogger<T>()
        {
            ILoggerFactory factory = GetService<ILoggerFactory>();
            return factory.CreateLogger<T>();
        }

        /// <summary>
        /// 获取指定类型的日志对象
        /// </summary>
        /// <param name="type">指定类型</param>
        /// <returns>日志对象</returns>
        public ILogger GetLogger(Type type)
        {
            ILoggerFactory factory = GetService<ILoggerFactory>();
            return factory.CreateLogger(type);
        }

        /// <summary>
        /// 获取指定名称的日志对象
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ILogger GetLogger(string name)
        {
            ILoggerFactory factory = GetService<ILoggerFactory>();
            return factory.CreateLogger(name);
        }

        /// <summary>
        /// 获取系统配置选项信息
        /// </summary>
        /// <returns>系统配置选项信息</returns>
        public MicroCloudOptions GetMicroCloudOptions()
        {
            //return _provider.GetService<IOptions<MicroCloudOptions>>()?.Value;    //为支持热重载，优先从单例获取实例。
            var options = _provider.GetMicroCloudOptions();

            return options;
        }

        /// <summary>
        /// 获取当前用户
        /// </summary>
        public ClaimsPrincipal GetCurrentUser()
        {
            try
            {
                IPrincipal user = GetService<IPrincipal>();
                return user as ClaimsPrincipal;
            }
            catch (System.Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取指定类型的当前组织机构编号
        /// </summary>
        /// <returns></returns>
        public T GetCurrentOrganizationId<T>()
        {
            try
            {
                IPrincipal user = GetService<IPrincipal>() as ClaimsPrincipal;
                if (user == null)
                {
                    return default;
                }
                return user.Identity.GetCurrentOrganizationId<T>();
            }
            catch (System.Exception)
            {
                return default;
            }
        }

        /// <summary>
        /// 获取用户当前组织机构编号
        /// </summary>
        /// <returns></returns>
        public string GetCurrentOrganizationId()
        {
            try
            {
                IPrincipal user = GetService<IPrincipal>() as ClaimsPrincipal;
                if (user == null)
                {
                    return null;
                }
                return user.Identity.GetCurrentOrganizationId();
            }
            catch (System.Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取指定类型的当前部门机构编号
        /// </summary>
        /// <returns></returns>
        public T GetCurrentDepartmentId<T>()
        {
            try
            {
                IPrincipal user = GetService<IPrincipal>() as ClaimsPrincipal;
                if (user == null)
                {
                    return default;
                }
                return user.Identity.GetCurrentDepartmentId<T>();
            }
            catch (System.Exception)
            {
                return default;
            }
        }

        /// <summary>
        /// 获取当前部门机构编号
        /// </summary>
        /// <returns></returns>
        public string GetCurrentDepartmentId()
        {
            try
            {
                IPrincipal user = GetService<IPrincipal>() as ClaimsPrincipal;
                if (user == null)
                {
                    return null;
                }
                return user.Identity.GetCurrentDepartmentId();
            }
            catch (System.Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取指定节点的选项值
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public string GetConfiguration(string path)
        {
            IConfiguration config = GetService<IConfiguration>() ?? _services.GetConfiguration();
            return config?[path];
        }

        /// <summary>
        /// 执行 <see cref="ServiceLifetime.Scoped"/> 生命周期的业务逻辑
        /// 1.当前处理 <see cref="ServiceLifetime.Scoped"/> 生命周期外，使用 CreateScope 创建 <see cref="ServiceLifetime.Scoped"/> 
        /// 生命周期的 ServiceProvider 来执行，并释放资源
        /// 2.当前处于 <see cref="ServiceLifetime.Scoped"/> 生命周期内，直接使用 <see cref="ServiceLifetime.Scoped"/> 的 ServiceProvider 来执行
        /// </summary>
        public void ExecuteScopedWork(Action<IServiceProvider> action, bool useHttpScope = true)
        {
            using IServiceScope scope = useHttpScope
                ? _provider.GetService<IHybridServiceScopeFactory>().CreateScope()
                : _provider.CreateScope();
            action(scope.ServiceProvider);
        }

        /// <summary>
        /// 异步执行 <see cref="ServiceLifetime.Scoped"/> 生命周期的业务逻辑
        /// 1.当前处理 <see cref="ServiceLifetime.Scoped"/> 生命周期外，使用 CreateScope 创建 <see cref="ServiceLifetime.Scoped"/> 
        /// 生命周期的 ServiceProvider来执行，并释放资源
        /// 2.当前处于 <see cref="ServiceLifetime.Scoped"/> 生命周期内，直接使用 <see cref="ServiceLifetime.Scoped"/> 的 ServiceProvider 来执行
        /// </summary>
        public async Task ExecuteScopedWorkAsync(Func<IServiceProvider, Task> action, bool useHttpScope = true)
        {
            using IServiceScope scope = useHttpScope
                ? _provider.GetService<IHybridServiceScopeFactory>().CreateScope()
                : _provider.CreateScope();
            await action(scope.ServiceProvider);
        }

        /// <summary>
        /// 执行 <see cref="ServiceLifetime.Scoped"/> 生命周期的业务逻辑，并获取返回值
        /// 1.当前处理 <see cref="ServiceLifetime.Scoped"/> 生命周期外，使用 CreateScope 创建 <see cref="ServiceLifetime.Scoped"/> 
        /// 生命周期的 ServiceProvider 来执行，并释放资源
        /// 2.当前处于 <see cref="ServiceLifetime.Scoped"/> 生命周期内，直接使用 <see cref="ServiceLifetime.Scoped"/> 的 ServiceProvider 来执行
        /// </summary>
        public TResult ExecuteScopedWork<TResult>(Func<IServiceProvider, TResult> func, bool useHttpScope = true)
        {
            using IServiceScope scope = useHttpScope
                ? _provider.GetService<IHybridServiceScopeFactory>().CreateScope()
                : _provider.CreateScope();
            return func(scope.ServiceProvider);
        }

        /// <summary>
        /// 执行 <see cref="ServiceLifetime.Scoped"/> 生命周期的业务逻辑，并获取返回值
        /// 1.当前处理 <see cref="ServiceLifetime.Scoped"/> 生命周期外，使用 CreateScope 创建 <see cref="ServiceLifetime.Scoped"/> 
        /// 生命周期的 ServiceProvider 来执行，并释放资源
        /// 2.当前处于 <see cref="ServiceLifetime.Scoped"/> 生命周期内，直接使用 <see cref="ServiceLifetime.Scoped"/> 的 ServiceProvider 来执行
        /// </summary>
        public async Task<TResult> ExecuteScopedWorkAsync<TResult>(Func<IServiceProvider, Task<TResult>> func, bool useHttpScope = true)
        {
            using IServiceScope scope = useHttpScope
                ? _provider.GetService<IHybridServiceScopeFactory>().CreateScope()
                : _provider.CreateScope();
            return await func(scope.ServiceProvider);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            _services = null;
            _provider = null;
            base.Dispose(disposing);
        }
        #endregion

    }
}